/** !Bitmap functions
This module implements bitmap functions for DEGFX. */

#ifndef MX__DEGFX_BITMAP_HEADER
#define MX__DEGFX_BITMAP_HEADER

#include "deds/atom.h"
#include "deds/alloc.h"
#include "deds/bool.h"
#include "deds/maxmin.h"
#include "deds/rectatom.h"
#include "detk/default.h"
#include "detk/file.h"
#include "degfx/colors.h"

#ifdef __cplusplus
extern "C" {
#endif

	/** !A bitmap type */
	typedef struct MX_BITMAP {
		union {
			MX_RECTATOM_DATA rectatom;
			MX_ATOM atom;
		} base;
		int _pitch;
		MX_RECT _clip;
		MX_PIXEL *_array;
	} MX_BITMAP;

#define MXBITMAP(b)   (&(b)->base.bitmap)

#ifdef MXDEBUG
#define MXBITMAP_DECLARE(d, w, h)    { { { { { 0, 0, 0, "bitmap"} }, { 0, 0, ((w) - 1), ((h) - 1)} } }, (w), { 0, 0, ((w) - 1), ((h) - 1)}, (d) }
#else
#define MXBITMAP_DECLARE(d, w, h)    { { { { { 0, 0, 0} }, { 0, 0, ((w) - 1), ((h) - 1)} } }, (w), { 0, 0, ((w) - 1), ((h) - 1)}, (d) }
#endif

/** !Create a bitmap */
MX_BITMAP *mx_bitmap(int x2, int y2);

/** !Load a bitmap from a TGA file */
	MX_BITMAP *mx_bitmap_tga(const char *filename);
    
/** !Load a bitmap from a GIF file */
	MX_BITMAP *mx_bitmap_gif(const char *filename);

/** !Load a bitmap from a PCX file */
	MX_BITMAP *mx_bitmap_pcx(const char *filename);

/** !Load a bitmap from a PCX file and convert it to greyscale */
	MX_BITMAP *mx_bitmap_pcx_greyscale(const char *filename);

/** !Make a complete copy of a bitmap */
	MX_BITMAP *mx_bitmap_clone(const MX_BITMAP * other);

/** !Set a bitmaps clipping area  */
	unsigned mx_bitmap_clip(MX_BITMAP * bitmap, const MX_RECT * newclip);

/** !Return a bitmaps clipping area */
	const MX_RECT *mx_bitmap_clip_get(const MX_BITMAP * bitmap);

/** !Offset a bitmap
Subsequent drawing on the bitmap will be offset. */
	void mx_bitmap_offset(MX_BITMAP * bitmap, int x1, int y1);

/** !Fast pixel-level iterator for a bitmap */
	typedef MX_PIXEL *MX_BITMAP_ITER;

/** !Return pixel-level iterator at a given position */
	MX_BITMAP_ITER mx_bitmap_iter(const MX_BITMAP * bitmap, int x1, int y1);
    
/** !Return pixel-level iterator at the top left position */
	MX_BITMAP_ITER mx_bitmap_begin(const MX_BITMAP * bitmap);
    
/** !Return pixel-level iterator at the lower right position */
	MX_BITMAP_ITER mx_bitmap_end(const MX_BITMAP * bitmap);

/** !Return pixel a a given position */
	MX_PIXEL mx_bitmap_getpixel(const MX_BITMAP * bitmap, int x1, int y1);

/** !Draw a pixel on a bitmap */
	void mx_bitmap_pixel(MX_BITMAP * bitmap, int x1, int y1, MX_PIXEL color);

/** !Draw a vertical line on a bitmap */
	void mx_bitmap_vline(MX_BITMAP * bitmap, int x1, int y1, int y2,
						 MX_PIXEL color);

/** !Draw a horizontal line on a bitmap */
	void mx_bitmap_hline(MX_BITMAP * bitmap, int x1, int y1, int x2,
						 MX_PIXEL color);

/** !Draw a line on a bitmap */
    void mx_bitmap_line(MX_BITMAP * bitmap, int x1, int y1, int x2, int y2,
						MX_PIXEL color);

/** !Draw a filled rectangle on a bitmap */
	void mx_bitmap_rectfill(MX_BITMAP * bitmap, int x1, int y1, int x2, int y2,
							MX_PIXEL color);
                            
/** !Clear a bitmap to a solid color */
	void mx_bitmap_clear(MX_BITMAP * bitmap, MX_PIXEL color);
    
/** !Blit a bitmap onto another bitmap
This function uses the pixel transparency of the source bitmap */
	void mx_bitmap_blit(const MX_BITMAP * src, MX_BITMAP * dest, int sx, int sy,
						int dx, int dy, int w, int h);

/** !Blit a bitmap onto another bitmap
This function uses no transparency */
	void mx_bitmap_blitcopy(const MX_BITMAP * src, MX_BITMAP * dest, int sx,
							int sy, int dx, int dy, int w, int h);
                            
/** !Blit a bitmap onto another bitmap
This function uses the a single transparency level */
	void mx_bitmap_blittrans(const MX_BITMAP * src, MX_BITMAP * dest, int sx,
							 int sy, int dx, int dy, int w, int h,
							 unsigned long trans);

/** !Stretch-blit a bitmap onto another bitmap
This function uses the pixel transparency of the source bitmap */
	void mx_bitmap_blitstretch(const MX_BITMAP * src, MX_BITMAP * dest, int sx,
							   int sy, int sw, int sh, int dx, int dy, int dw,
							   int dh);
                               
/** !Draw a box on a bitmap */
	void mx_bitmap_box(MX_BITMAP * bitmap, int x1, int y1, int x2, int y2,
					   int width, MX_PIXEL light, MX_PIXEL dark);
                       
/** !Draw a frame on a bitmap */
	void mx_bitmap_frame(MX_BITMAP * bitmap, int x1, int y1, int x2, int y2,
						 int width, MX_PIXEL light, MX_PIXEL dark,
						 MX_PIXEL fill);

/** !Blitting function for drawing gui objects */
	void mx_bitmap_decorate(const MX_BITMAP * src, MX_BITMAP * dest, int x,
							int y, int x1, int y1, int x2, int y2);

/** !Check if two bitmaps overlap on any pixels
Pixel level transparency is taken into account */
	unsigned mx_bitmap_collision(const MX_BITMAP * src, const MX_BITMAP * dest,
								 int sx, int sy, int dx, int dy,
								 unsigned int thresh);

/** !Get an iterator to a given position on the screen */
#define mx_iter(x,y)                   mx_bitmap_iter(MXSCREEN,(x),(y))

/** !Return the pixel at a given position on the screen */
#define mx_getpixel(x,y)               mx_bitmap_getpixel(MXSCREEN,(x),(y))

/** !Draw a pixel on the screen */
#define mx_pixel(x,y,c)                mx_bitmap_pixel(MXSCREEN,(x),(y),(c))

/** !Draw a vertical line on the screen */
#define mx_vline(x,y1,y2,c)            mx_bitmap_vline(MXSCREEN,(x),(y1),(y2),(c))

/** !Draw a horizontal line on the screen */
#define mx_hline(x1,y,x2,c)            mx_bitmap_hline(MXSCREEN,(x1),(y),(x2),(c))

/** !Draw a line on the screen */
#define mx_line(x1,y1,x2,y2,c)         mx_bitmap_line(MXSCREEN,(x1),(y1),(x2),(y2),(c))

/** !Draw a filled rectangle on the screen */
#define mx_rectfill(x1,y1,x2,y2,c)     mx_bitmap_rectfill(MXSCREEN,(x1),(y1),(x2),(y2),(c))

/** !Clear the screen to a solid color */
#define mx_clear(c)                    mx_bitmap_clear(MXSCREEN,(c))

/** !Blit a bitmap onto the screen
This function uses the pixel transparency of the source bitmap */
#define mx_blit(s,sx,sy,dx,dy,w,h)     mx_bitmap_blit((s),MXSCREEN,(sx),(sy),(dx),(dy),(w),(h))

/** !Blit a bitmap onto the screen
This function uses no transparency */
#define mx_blitcopy(s,sx,sy,dx,dy,w,h) mx_bitmap_blitcopy((s),MXSCREEN,(sx),(sy),(dx),(dy),(w),(h))

/** !Blit a bitmap onto the screen
This function uses the a single transparency level */
#define mx_blittrans(s,sx,sy,dx,dy,w,h,t) mx_bitmap_blittrans((s),MXSCREEN,(sx),(sy),(dx),(dy),(w),(h),(t))

/** !Stretch-blit a bitmap onto the screen
This function uses the pixel transparency of the source bitmap */
#define mx_blitstretch(s,sx,sy,sw,sh,dx,dy,dw,dh) mx_bitmap_blitstretch((s),MXSCREEN,(sx),(sy),(sw),(sh),(dx),(dy),(dw),(dh))

/** !Draw a box on the screen */
#define mx_box(x1,y1,x2,y2,w,l,d)      mx_bitmap_box(MXSCREEN,(x1),(y1),(x2),(y2),(w),(l),(d))

/** !Draw a frame on the screen */
#define mx_frame(x1,y1,x2,y2,w,l,d,f)  mx_bitmap_frame(MXSCREEN,(x1),(y1),(x2),(y2),(w),(l),(d),(f))

/** !Blitting function for drawing gui objects on the screen */
#define mx_decorate(s,x,y,x1,y1,x2,y2) mx_bitmap_decorate((s),MXSCREEN,(x),(y),(x1),(y1),(x2),(y2))

	extern void mx__fasthline(MX_BITMAP * bitmap, int x1, int y1, int x2,
							  MX_PIXEL color);

#define MX__CLIP_PIXEL(rect, xa, ya) \
   (((xa) < ((rect).x1)) ||        \
    ((xa) > ((rect).x2)) ||        \
    ((ya) < ((rect).y1)) ||        \
    ((ya) > ((rect).y2)))          \

#define MX__CLIP_BLIT(src, dest, sx, sy, dx, dy, w, h) \
do {                                                 \
    MX_RECT srca, dsta;                              \
                                                     \
    srca.x1 = (sx);                                  \
    srca.y1 = (sy);                                  \
    srca.x2 = (sx) + (w);                            \
    srca.y2 = (sy) + (h);                            \
                                                     \
    MXRECT_INTERSECT((src), srca, srca);             \
    if (!MXRECT_VALID(srca))                         \
        return;                                      \
                                                     \
    (w) = srca.x2 - srca.x1;                         \
    (h) = srca.y2 - srca.y1;                         \
                                                     \
    dsta.x1 = (dx);                                  \
    dsta.y1 = (dy);                                  \
    dsta.x2 = (dx) + (w);                            \
    dsta.y2 = (dy) + (h);                            \
                                                     \
    MXRECT_INTERSECT((dest), dsta, dsta);            \
    if (!MXRECT_VALID(dsta))                         \
        return;                                      \
                                                     \
    (w) = MX_MIN((w), dsta.x2 - dsta.x1);             \
		(h) = MX_MIN((h), dsta.y2 - dsta.y1);             \
                                                     \
    (sx) = srca.x1 + dsta.x1 - (dx);                 \
    (sy) = srca.y1 + dsta.y1 - (dy);                 \
    (dx) = dsta.x1;                                  \
    (dy) = dsta.y1;                                  \
                                                     \
    assert((w) >= 0);                              \
    assert((h) >= 0);                              \
    assert((sx) >= 0);                             \
    assert((sy) >= 0);                             \
    assert((dx) >= 0);                             \
    assert((dy) >= 0);                             \
} while (0)

#ifdef __cplusplus
}
#endif
#endif
